/*
 *
 *  * Copyright:  2018 smarabbit studio.
 *  *
 *  *  Licensed under the Confluent Community License; you may not use this file
 *  *  except in compliance with the License.  You may obtain a copy of the License at
 *  *
 *  *  http://www.confluent.io/confluent-community-license
 *  *
 *  *  Unless required by applicable law or agreed to in writing, software
 *  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  *  specific language governing permissions and limitations under the License.
 *  *
 *  *  @作   者： 黄开晖 (117227773@qq.com)
 *  *  @日   期:    ${DATE}
 *
 */

package com.massyframework.beanskin.web.utils;


import java.util.EnumSet;
import java.util.List;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.assembly.Assembly;
import com.massyframework.beanskin.assembly.AssemblyConfig;
import com.massyframework.beanskin.initparam.InitParameters;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.web.filter.DelegateFilter;

/**
 * {@link FilterRegistrationUtils}提供过滤器注册的工具类
 */
public class FilterRegistrationUtils {

    private static final String PREFIX        = "filter";
    private static final String PREFIX_INIT   = PREFIX.concat(".").concat("init-param");
    private static final String FILTER_NAME   = "name";
    private static final String FILTER_URL_PATTERN    = "url-pattern";
    private static final String FILTER_ISMATCH_AFTER  = "isMatchAfter";
    private static final String FILTER_ASYNCSUPPORTED = "async-supported";

    /**
     * 从<code>initParams</code>中截取Filter参数
     *
     * @param config {@link AssemblyConfig}, 装配件配置
     * @return {@link InitParameters}
     */
    public static InitParameters getFilterParameters(AssemblyConfig config) {
        return config.subset(PREFIX);
    }

    /**
     * 根据<code>servletParams</code>创建{@link ServletRegistration}
     *
     * @param context             {@link ServletContext}, ServletContext上下文
     * @param assembly            {@link ServiceExportableModule}, 装配件
     * @param defaultFilterName   {@link String},缺省的Servlet名称
     * @param defaultAsyncSupport {@link String), 缺省的异步支持
     * @return {@link ServletRegistration}
     */
    public static FilterRegistration.Dynamic createFilterRegistration(
            ServletContext context,
            Assembly assembly,
            String defaultFilterName,
            String defaultAsyncSupport) throws ServletException{
        InitParameters initParams = assembly.getConfig();
        return createFilterRegistration(
                context,
                assembly,
                initParams.subset(PREFIX),
                initParams.subset(PREFIX_INIT),
                defaultFilterName,
                defaultAsyncSupport);
    }

    /**
     * 根据<code>servletParams</code>创建{@link ServletRegistration}
     *
     * @param context          {@link ServletContext}, ServletContext上下文
     * @param assembly         {@link Module}, 装配件
     * @param filterSubParams  {@link InitParameters}, 使用{@link #getFilterParameters(AssemblyConfig)}获取的初始化子参数
     * @aaram filterInitParams (@link InitParameters}, filterSubParams使用{@link InitParameters#subset(String)}获取的初始化参数。
     * @param defaultFilterName {@link String}, 缺省的Filter名称
     * @param defaultAsyncSupport {@link String}, 缺省的异步支持模式
     * @return {@link FilterRegistration}
     */
    public static FilterRegistration.Dynamic createFilterRegistration(
            ServletContext context,
            Module<?> assembly,
            InitParameters filterSubParams,
            InitParameters filterInitParams,
            String defaultFilterName,
            String defaultAsyncSupport) throws ServletException {

        try {
            String filterName = filterSubParams.getParameter(FILTER_NAME, defaultFilterName);
            if (filterName == null){
                throw new ServletException(
                		String.format("cannot found initparams: name=\"filter.%s\" , please set it.", FILTER_NAME));
            }
            FilterRegistration.Dynamic result = context.addFilter(filterName, DelegateFilter.class.getName());
            if (result == null){
                throw new ServletException(
                		String.format("filter is exists: filterName = \"%s\".",filterName));
            }

            //url-pattern的变体，
            String text = filterSubParams.getParameter(FILTER_URL_PATTERN);
            if (text == null) {
                throw new ServletException("cannot found filter parameter: \"filter.url-pattern\" .");
            }


            String[] urlPattern = text.split(",");
            text = filterSubParams.getParameter(FILTER_ISMATCH_AFTER, "true");
            result.addMappingForUrlPatterns(
                    EnumSet.allOf(DispatcherType.class), Boolean.parseBoolean(text), urlPattern);

            //异步支持
            String asyncSupported = filterSubParams.getParameter(FILTER_ASYNCSUPPORTED, "true");
            boolean supported = Boolean.parseBoolean(asyncSupported);
            result.setAsyncSupported(supported);


            //设置属性
            List<String> names = filterInitParams.getParameterNames();
            for (String name : names) {
                String value = filterInitParams.getParameter(name);
                result.setInitParameter(name, value);
            }
            result.setInitParameter(ServiceReference.MODULE_GROUPID, assembly.getGroupId());
            result.setInitParameter(ServiceReference.MODULE_MODULEID, assembly.getModuleId());
            result.setInitParameter(ServiceReference.MODULE_VERSION, assembly.getVersion().toString());
            return result;
        } catch (Exception e) {
            throw new ServletException("create filter failed.", e);
        }
    }
}
